package org.activequant.data.retrieval.ib;

import org.activequant.core.domainmodel.InstrumentSpecification;
import org.activequant.core.domainmodel.data.Quote;
import org.activequant.core.types.TimeFrame;
import org.activequant.data.annotations.Vendor;
import org.activequant.data.retrieval.IQuoteSubscriptionSource;
import org.activequant.data.retrieval.ISubscription;
import org.activequant.data.retrieval.SubscriptionSourceBase;
import org.activequant.util.ib.IBTwsConnection;
import org.activequant.util.pattern.events.IEventListener;
import org.apache.log4j.Logger;


/**
 * 
 * Quote events subscription source. Uses {@link IBTwsConnection} class
 * as a backend for requesting and receiving Quote events from Interactive Brokers.
 * <br>
 * IBQuoteSource extends SubscriptionSourceBase&lt;Quote&gt; implements IQuoteSubscriptionSource.<br>
 * Holds the following associated variables:
 * <ul>
 * <li>connection(IBTwsConnection)</li>
 * </ul>
 * Holds the following inherited variables:
 * <ul>
 * <li>activeBackends(Map&lt;Topic, Subscription&gt;)</li>
 * <li>activeSubscriptions(Queue&lt;SubscriptionDelegate&gt;)</li>
 * </ul>
 * <b>History:</b><br>
 *  - [10.09.2007] Created (?)<br>
 *  - [29.09.2007] cleanup + moved to new domain model (Erik Nijkamp)<br>
 *  - [28.10.2007] moved to new subscription source data model (Mike Kroutikov)<br>
 *
 *  @author Activequant Contributors
 */
@Vendor("IB")
public class IBQuoteSource extends SubscriptionSourceBase<Quote> implements IQuoteSubscriptionSource {
	/**
	 * private final IBTwsConnection connection;
	 */
	private final IBTwsConnection connection; 
	
	protected final static Logger log = Logger.getLogger(IBQuoteSource.class);
	/**
	 * constructs an IBQuoteSource(extends SubscriptionSourceBase&lt;Quote&gt; implements IQuoteSubscriptionSource) using the given connection(IBTwsConnection)
	 * to set its associated connection(IBTwsConnection).
	 * @param connection
	 */
	public IBQuoteSource(IBTwsConnection connection){
		super();
		this.connection = connection;
	}
	/**
	 * QuoteSubscription extends Subscription. Holds the following associated variables:
	 * <ul>
	 * <li>spec(InstrumentSpecification)</li>
	 * <li>listener(IEventListener&lt;Quote&gt;)</li>
	 * </ul>
	 * Holds the following inherited variables:
	 * <ul>
	 * <li>isActive(AtomicBoolean)</li>
	 * <li>refCount(AtomicInteger)</li>
	 * <li>instrument(InstrumentSpecification)</li>
	 * <li>event(Event&lt;Quote&gt;)</li>
	 * </ul>
	 * @author Dimitar
	 *
	 */
	private class QuoteSubscription extends Subscription {
		/**
		 * private final InstrumentSpecification spec;
		 */
		private final InstrumentSpecification spec;
		/**
		 * constructs a QuoteSubscription(extends Subscription) using the given s(InstrumentSpecification) to set its associated spec(InstrumentSpecification)
		 * @param s
		 */
		QuoteSubscription(InstrumentSpecification s) {
			spec = s;
		}
		/**
		 * private final IEventListener&lt;Quote&gt; listener = new IEventListener&lt;Quote&gt;() {...}<br/>
		 * A listener that re-fires any event(Quote)
		 */
		private final IEventListener<Quote> listener = new IEventListener<Quote>() {
			public void eventFired(Quote event) {
				fireEvent(event);
			}
		};
		/**
		 * Subscribes the associated listener(IEventListener&lt;Quote&gt;) for real time market data from the connection(IBTwsConnection) for the associated spec(InstrumentSpecification)
		 */
		@Override
		protected void handleActivate() {
			connection.subscribeToQuote(listener, spec);
		}
		/**
		 * Unsubscribes the associated listener(IEventListener&lt;Quote&gt;) from listening to real time market data from the connection(IBTwsConnection) for the associated spec(InstrumentSpecification)
		 */
		@Override
		protected void handleCancel() {
			connection.unsubscribeFromQuote(listener, spec);
		}
	}
	/**
	 * creates and returns a QuoteSubscription(extends Subscription) using the given spec(InstrumentSpecification) to set its associated spec(InstrumentSpecification).<br/>
	 * The given timeFrame(TimeFrame) is not used.
	 */
	@Override
	protected QuoteSubscription createSubscription(InstrumentSpecification spec, TimeFrame timeFrame) {
		return new QuoteSubscription(spec);
	}
	/**
	 * Returns/creates a ISubscription&lt;Quote&gt; for the given spec(InstrumentSpecification) and TIMEFRAME_1_TICK.
	 */
	public ISubscription<Quote> subscribe(InstrumentSpecification spec) {
		return subscribe(spec, TimeFrame.TIMEFRAME_1_TICK);
	}
}
